home *** CD-ROM | disk | FTP | other *** search
- /**
- *
- * Name pcsetisr -- Set interrupt service routine
- *
- * Synopsis ercode = pcsetisr(intype,pfunc,stksize,pvector,pisrblk);
- * int ercode Error return code
- * int intype Interrupt type number
- * unsigned (*pfunc)() Pointer to interrupt service routine
- * int stksize Stack size needed for ISR
- * ADS *pvector Previous interrupt vector for the
- * specified interrupt type.
- * ISRCTRL **pisrblk Pointer to ISR control block
- *
- * Description pcsetisr sets the interrupt vector to point to an ISR
- * control block. The control block is used by the ISR dis-
- * patcher function to set up the ISR stack, call the actual
- * ISR function and handle the interrupt protocol. The
- * address of the control block is placed in the interrupt
- * vector; the first bytes of the control block have the code
- * necessary to invoke the ISR dispatcher. The control block
- * is a structure, space for which is allocated on the heap,
- * defined as follows:
- *
- * call instruction: The far call instruction starts with
- * the opcode of 9A then the IP and CS values for the
- * ISR dispatcher.
- * ISR stack segment and pointer: The stack segment is set by
- * PCISRSTK, and placed in variable external to PCSETISR.
- * The stack pointer is the requested size of the stack.
- * Data segment value of program setting up the ISR. The ISR
- * will use the same data segment.
- * Space to store the invoking programs stack segment and
- * stack pointer. Because the ISR dispatcher must alter
- * the stack, it must be restored before the interrupt
- * service returns.
- * Pointer to the C function which processes the interrupt,
- * that is the Interrupt Service Routine (ISR).
- *
- * The original interrupt vector is returned so that it
- * may be restored if the ISR is to be disabled, and a
- * pointer to the control block is returned so space can be
- * freed when it is no longer needed.
- *
- * Returns ercode The return code is 0 if the vector is
- * is successfully set; other values are:
- * 1 - Interrupt type out of range
- * 2 - Cannot allocate space for ISR control
- *
- * Version 1.1 (C)Copyright Blaise Computing Inc. 1983, 1984
- *
- **/
- #include <compiler.h>
-
- #if LDATA
- #define NULL 0L
- #else
- #define NULL 0
- #endif
-
- #define utoutrng(a,l,h) (((a)<(l)||(a)>(h))?1:0) /* Is a out of range? */
-
- struct segads /* Offset, segment address type */
- {
- unsigned r;
- unsigned s;
- };
- #define ADS struct segads /* Abbreviation */
-
- struct isr_control
- {
- unsigned fcall_opcode; /* Far call op code 9A */
- #if LPROG
- int (*isrdisp)(); /* Pointer to ISR dispatcher */
- #else
- int (*isrdisp)();
- unsigned isrdisp_cs; /* Code segment when it is NEAR */
- #endif
- unsigned isrss; /* ISR stack segment */
- unsigned isrsp; /* ISR stack pointer */
- unsigned isrstksize; /* ISR stack size */
- unsigned isrds; /* ISR data segment */
- unsigned savess; /* Location to save SS and SP */
- unsigned savesp; /* from invoking program */
- unsigned (*isr)(); /* Pointer to ISR. Note that */
- }; /* 2 or 4 bytes depending on the*/
- /* memory model used. */
- #define ISRCTRL struct isr_control
-
- extern unsigned isrss; /* ISR stack information from */
- extern unsigned isrstk_base; /* PCSISRSTK. */
-
- int pcsetisr(intype,pfunc,stksize,pvector,pisrblk)
- int intype,stksize;
- unsigned (*pfunc)();
- ADS *pvector;
- ISRCTRL **pisrblk;
- {
-
- ADS isrblk_ads;
- char *calloc();
- extern int invisr(); /* ISR dispatcher */
- unsigned cs,ss,ds,es;
- #if CI201A & LDATA
- unsigned long ptrtoabs();
- #endif
-
- if (utoutrng(intype,0,255))
- return(1);
-
- pcretvec(intype,pvector); /* Return the interrupt vector */
-
- *pisrblk = (ISRCTRL *)calloc(1,sizeof(ISRCTRL));
- if (*pisrblk == NULL)
- return(2);
- utsreg(&cs,&ss,&ds,&es);
-
- (*pisrblk)->fcall_opcode = 0x9a00;
- #if LPROG
- (*pisrblk)->isrdisp = invisr; /* ISR dispatcher address */
- #else
- (*pisrblk)->isrdisp = invisr;
- (*pisrblk)->isrdisp_cs = cs;
- #endif
- (*pisrblk)->isrss = isrss; /* ISR stack segment and pointer */
- (*pisrblk)->isrsp = isrstk_base + 2;
- (*pisrblk)->isrstksize = stksize;
- (*pisrblk)->isrds = ds; /* ISR data segment */
- (*pisrblk)->isr = pfunc; /* Interrupt service routine */
-
- /* Now load the interrupt vector with the segment and offset */
- /* address of the ISR control block. */
-
- #if LDATA
- #if CI201A
- isrblk_ads.s = (unsigned)((ptrtoabs(*pisrblk) & 0xffff0L) >> 4L);
- isrblk_ads.r = (unsigned)(ptrtoabs(*pisrblk) & 0xfL);
- #else
- isrblk_ads.s = (unsigned)(((long)(*pisrblk) & 0xffff0L) >> 4L);
- isrblk_ads.r = (unsigned)((long)(*pisrblk) & 0xfL);
- #endif
- #else
- isrblk_ads.s = ds;
- isrblk_ads.r = *pisrblk;
- #endif
- isrblk_ads.r++;
- pcsetvec(intype,&isrblk_ads);
-
- return(0);
-
- }